from typing import List, Dict, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, UploadFile, File
from sqlalchemy.orm import Session
from app.api import deps
from app.crud import question as crud_question
from app.schemas.question import (
    QuestionCreate,
    QuestionUpdate,
    QuestionInDB,
    QuestionList,
    QuestionFilter,
    QuestionStatus,
    QuestionImportResult
)
import pandas as pd
import json
import markdown
from io import StringIO, BytesIO
import re
import logging
import traceback

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

router = APIRouter()

# 题目类型映射
QUESTION_TYPE_MAP: Dict[str, str] = {
    "单选题": "single_choice",
    "多选题": "multiple_choice",
    "简答题": "short_answer",
    "编程题": "coding",
    "对话题": "dialog",
    # 反向映射
    "single_choice": "单选题",
    "multiple_choice": "多选题",
    "short_answer": "简答题",
    "coding": "编程题",
    "dialog": "对话题"
}

# 难度映射
DIFFICULTY_MAP: Dict[str, str] = {
    "简单": "easy",
    "中等": "medium",
    "困难": "hard",
    # 反向映射
    "easy": "简单",
    "medium": "中等",
    "hard": "困难"
}

def convert_question_type(type_str: str) -> str:
    """
    转换题目类型（中文 -> 英文）
    """
    type_str = type_str.strip()
    if type_str in QUESTION_TYPE_MAP:
        return QUESTION_TYPE_MAP[type_str]
    # 如果已经是英文，直接返回
    if type_str in QUESTION_TYPE_MAP.values():
        return type_str
    raise ValueError(f"不支持的题目类型: {type_str}")

def convert_difficulty(difficulty_str: str) -> str:
    """
    转换难度（中文 -> 英文）
    """
    difficulty_str = difficulty_str.strip()
    if difficulty_str in DIFFICULTY_MAP:
        return DIFFICULTY_MAP[difficulty_str]
    # 如果已经是英文，直接返回
    if difficulty_str in DIFFICULTY_MAP.values():
        return difficulty_str
    raise ValueError(f"不支持的难度级别: {difficulty_str}")

def process_tags(tags_str: any) -> Optional[str]:
    """
    处理标签字符串，转换为 JSON 字符串数组
    """
    if pd.isna(tags_str) or tags_str is None:
        return None
    
    tags_list = [tag.strip() for tag in str(tags_str).split(',') if tag.strip()]
    if not tags_list:
        return None
    
    return json.dumps(tags_list)

@router.get("/", response_model=QuestionList)
def get_questions(
    db: Session = Depends(deps.get_db),
    type: str = None,
    difficulty: str = None,
    topic: str = None,
    status: QuestionStatus = None,
    tags: List[str] = Query(None),
    search: str = None,
    page: int = 1,
    page_size: int = 10
):
    """
    获取题目列表，支持多种过滤条件和分页
    """
    filter_params = QuestionFilter(
        type=type,
        difficulty=difficulty,
        topic=topic,
        status=status,
        tags=tags,
        search=search,
        page=page,
        page_size=page_size
    )
    questions, total = crud_question.get_questions(db, filter_params)
    return {
        "total": total,
        "items": questions
    }

@router.post("/", response_model=QuestionInDB)
def create_question(
    *,
    db: Session = Depends(deps.get_db),
    question_in: QuestionCreate
):
    """
    创建新题目
    """
    question = crud_question.create_question(db, question_in)
    return question

@router.get("/{question_id}", response_model=QuestionInDB)
def get_question(
    question_id: int,
    db: Session = Depends(deps.get_db)
):
    """
    获取指定题目详情
    """
    question = crud_question.get_question(db, question_id)
    if not question:
        raise HTTPException(status_code=404, detail="Question not found")
    return question

@router.put("/{question_id}", response_model=QuestionInDB)
def update_question(
    *,
    db: Session = Depends(deps.get_db),
    question_id: int,
    question_in: QuestionUpdate
):
    """
    更新题目
    """
    question = crud_question.update_question(db, question_id, question_in)
    if not question:
        raise HTTPException(status_code=404, detail="Question not found")
    return question

@router.delete("/{question_id}")
def delete_question(
    *,
    db: Session = Depends(deps.get_db),
    question_id: int
):
    """
    删除题目
    """
    success = crud_question.delete_question(db, question_id)
    if not success:
        raise HTTPException(status_code=404, detail="Question not found")
    return {"status": "success"}

@router.post("/import", response_model=QuestionImportResult)
async def import_questions(
    *,
    db: Session = Depends(deps.get_db),
    file: UploadFile = File(...)
):
    """
    批量导入题目，支持 Excel、Markdown、JSON 格式
    """
    # 检查文件类型
    file_ext = file.filename.split('.')[-1].lower()
    if file_ext not in ['xlsx', 'xls', 'md', 'json']:
        raise HTTPException(
            status_code=400,
            detail="Unsupported file format. Please upload Excel, Markdown, or JSON file."
        )
    
    # 读取文件内容
    content = await file.read()
    
    total_processed = 0
    successfully_imported = 0
    
    try:
        questions_to_create = []
        if file_ext in ['xlsx', 'xls']:
            try:
                # 处理 Excel 文件
                logger.info(f"开始处理 Excel 文件: {file.filename}")
                df = pd.read_excel(BytesIO(content))
                logger.info(f"Excel 文件读取成功，共 {len(df)} 行数据")
                logger.info(f"Excel 列名: {df.columns.tolist()}")
                total_processed = len(df)
                
                # 检查必需的列是否存在
                required_columns = ['title', 'type', 'answer', 'difficulty', 'topic']
                missing_columns = [col for col in required_columns if col not in df.columns]
                if missing_columns:
                    raise HTTPException(
                        status_code=400,
                        detail=f"Excel 文件缺少必需的列: {', '.join(missing_columns)}"
                    )
                
                # 处理每一行数据
                for index, row in df.iterrows():
                    try:
                        # 检查必需字段是否为空
                        for col in required_columns:
                            if pd.isna(row[col]):
                                raise ValueError(f"第 {index + 2} 行的 {col} 字段不能为空")
                        
                        # 打印当前行的数据
                        logger.info(f"处理第 {index + 2} 行数据:")
                        for col in df.columns:
                            logger.info(f"  {col}: {row[col]}")
                        
                        question_data = {
                            'title': str(row['title']).strip(),
                            'type': convert_question_type(str(row['type']).strip()),
                            'answer': str(row['answer']).strip(),
                            'difficulty': convert_difficulty(str(row['difficulty']).strip()),
                            'topic': str(row['topic']).strip(),
                            'options': str(row['options']).strip() if 'options' in row and not pd.isna(row['options']) else None,
                            'tags': process_tags(row['tags']) if 'tags' in row else None,
                            'explanation': str(row['explanation']).strip() if 'explanation' in row and not pd.isna(row['explanation']) else None,
                            'reference_links': str(row['reference_links']).strip() if 'reference_links' in row and not pd.isna(row['reference_links']) else None,
                        }
                        questions_to_create.append(QuestionCreate(**question_data))
                        logger.info(f"成功处理第 {index + 2} 行数据")
                    except ValueError as e:
                        logger.error(f"第 {index + 2} 行数据错误: {str(e)}")
                    except Exception as e:
                        logger.error(f"处理第 {index + 2} 行数据时发生错误: {str(e)}")
                        logger.error(f"错误详情: {traceback.format_exc()}")
                
            except pd.errors.EmptyDataError:
                logger.error("Excel 文件为空")
                raise HTTPException(
                    status_code=400,
                    detail="Excel 文件为空"
                )
            except Exception as e:
                logger.error(f"处理 Excel 文件时发生错误: {str(e)}")
                logger.error(f"错误详情: {traceback.format_exc()}")
                raise HTTPException(
                    status_code=400,
                    detail=f"处理 Excel 文件时发生错误: {str(e)}"
                )
                
        elif file_ext == 'json':
            # 处理 JSON 文件
            json_data = json.loads(content)
            if not isinstance(json_data, list):
                raise HTTPException(
                    status_code=400,
                    detail="JSON file must contain an array of questions"
                )
            total_processed = len(json_data)
            for i, item in enumerate(json_data):
                try:
                    if isinstance(item.get('type'), str):
                        item['type'] = convert_question_type(item['type'])
                    if isinstance(item.get('difficulty'), str):
                        item['difficulty'] = convert_difficulty(item['difficulty'])
                    if 'tags' in item and isinstance(item.get('tags'), (str, list)):
                        # 如果是字符串，按照逗号分隔，并转为json string
                        if isinstance(item.get('tags'), str):
                            item['tags'] = process_tags(item['tags'])
                        # 如果是列表，直接转为json string
                        elif isinstance(item.get('tags'), list):
                            item['tags'] = json.dumps(item['tags'])
                        
                    questions_to_create.append(QuestionCreate(**item))
                except ValueError as e:
                    logger.error(f"第 {i + 1} 条 JSON 数据错误: {str(e)}")
                except Exception as e:
                    logger.error(f"处理第 {i + 1} 条 JSON 数据时发生错误: {str(e)}")
                    logger.error(f"错误详情: {traceback.format_exc()}")
                
        elif file_ext == 'md':
            # 处理 Markdown 文件
            md_content = content.decode('utf-8')
            # 使用正则表达式匹配题目
            question_pattern = r'##\s*(.*?)\n\n(?:类型|Type):\s*(.*?)\n(?:难度|Difficulty):\s*(.*?)\n(?:主题|Topic):\s*(.*?)\n(?:答案|Answer):\s*(.*?)\n(?:选项|Options):\s*```\n(.*?)\n```\n(?:解释|Explanation):\s*(.*?)(?=\n\n##|\Z)'
            matches = re.finditer(question_pattern, md_content, re.DOTALL)
            
            # Convert matches to a list to get total_processed before iterating
            all_matches = list(matches)
            total_processed = len(all_matches)

            for i, match in enumerate(all_matches):
                try:
                    title, type_, difficulty, topic, answer, options, explanation = match.groups()
                    question_data = {
                        'title': title.strip(),
                        'type': convert_question_type(type_.strip()),
                        'answer': answer.strip(),
                        'difficulty': convert_difficulty(difficulty.strip()),
                        'topic': topic.strip(),
                        'options': options.strip(),
                        'explanation': explanation.strip() if explanation else None,
                    }
                    question_data['tags'] = process_tags(question_data.get('tags'))
                    
                    questions_to_create.append(QuestionCreate(**question_data))
                except ValueError as e:
                    logger.error(f"第 {i + 1} 题 Markdown 数据错误: {str(e)}")
                except Exception as e:
                    logger.error(f"处理第 {i + 1} 题 Markdown 数据时发生错误: {str(e)}")
                    logger.error(f"错误详情: {traceback.format_exc()}")
                
        if not questions_to_create:
            raise HTTPException(
                status_code=400,
                detail="No valid questions found in the file or all questions had errors"
            )
            
        imported_questions = crud_question.bulk_create_questions(db, questions_to_create)
        successfully_imported = len(imported_questions)
        
        return QuestionImportResult(
            total_processed=total_processed,
            successfully_imported=successfully_imported,
            message=f"成功导入 {successfully_imported} 条题目，共处理 {total_processed} 条题目。"
        )
        
    except HTTPException as e:
        raise e # 重新抛出已处理的 HTTPException
    except Exception as e:
        logger.error(f"处理文件时发生错误: {str(e)}")
        logger.error(f"错误详情: {traceback.format_exc()}")
        raise HTTPException(
            status_code=400,
            detail=f"Error processing file: {str(e)}"
        ) 